﻿namespace JoinBox.Basal;

using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Drawing;

public partial class WindowsAPI
{
    /// <summary>
    /// 获取一个焦点窗口(用户当前工作的窗口)的句柄
    /// </summary>
    /// <returns></returns>
    [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
    public static extern IntPtr GetForegroundWindow();

    /// <summary>
    /// 获取一个焦点窗口(用户当前工作的窗口)的窗体标题
    /// </summary>
    public static string GetForegroundWindowText()
    {
        var title = new StringBuilder(256);
        var ip = GetForegroundWindow();
        if (ip != IntPtr.Zero)
            GetWindowText(ip, title, title.Capacity);
        return title.ToString();
    }

    /// <summary>
    /// 创建窗口
    /// </summary>
    [DllImport("user32.dll", EntryPoint = "CreateWindowEx", SetLastError = true)]
    public static extern IntPtr CreateWindowEx(
        int dwExStyle, string lpClassName, string lpWindowName, int dwStyle,
        int X, int Y, int nWidth, int nHeight, IntPtr hWndParent, IntPtr hMenu,
        IntPtr hInstance, int lpParam);

    /// <summary>
    /// 方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递
    /// </summary>
    /// <param name="hhwnd"></param>
    /// <param name="msg"></param>
    /// <param name="wparam"></param>
    /// <param name="lparam"></param>
    /// <returns></returns>
    [DllImport("user32.dll")]
    static extern bool PostMessage(int hhwnd, uint msg, IntPtr wparam, IntPtr lparam);


    /// <summary>
    /// 该函数可以获得与调用线程的消息队列相关的活动窗口的窗口句柄
    /// </summary>
    /// <returns></returns>
    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr GetActiveWindow();

    /// <summary>
    /// 根据坐标获取窗口句柄
    /// </summary>
    /// <param name="Point"></param>
    /// <returns></returns>
    [DllImport("user32")]
    public static extern IntPtr WindowFromPoint(Point Point);

    /// <summary>
    /// 销毁指定的窗口
    /// </summary>
    /// <param name="handle"></param>
    /// <returns></returns>
    [DllImport("user32")]
    public static extern bool DestroyWindow(IntPtr handle);


    /// <summary>
    /// 函数获得一个指定子窗口的父窗口句柄
    /// </summary>
    /// <param name="hWnd"></param>
    /// <returns></returns>
    [DllImport("user32.dll", EntryPoint = "GetParent")]
    public static extern IntPtr GetParent(IntPtr hWnd);

    // https://baike.baidu.com/item/SetWindowPos/6376849?fr=aladdin
    /// <summary>
    /// 排序窗口
    /// 改变一个(子窗口,弹出式窗口,顶层窗口)的尺寸,位置,Z序.
    /// 根据它们在屏幕上出现的顺序排序,顶层窗口设置的级别最高,
    /// 并且被设置为Z序的第一个窗口.
    /// </summary>
    /// <param name="hWnd">在z序中的位于被置位的窗口前的窗口句柄</param>
    /// <param name="hWndInsertAfter">用于标识在z-顺序的此 CWnd 对象之前的 CWnd 对象。
    /// 如果uFlags参数中设置了SWP_NOZORDER标记则本参数将被忽略。可为下列值之一：</param>
    /// <param name="X">以客户坐标指定窗口新位置的左边界。</param>
    /// <param name="Y">以客户坐标指定窗口新位置的顶边界。</param>
    /// <param name="cx">以像素指定窗口的新的宽度。</param>
    /// <param name="cy">以像素指定窗口的新的高度。</param>
    /// <param name="uFlags">窗口尺寸和定位的标志。该参数可以是下列值的组合：</param>
    /// <returns></returns>
#if NET35
    [DllImport("user32.dll", CharSet = CharSet.Unicode, EntryPoint = "SetWindowPos")]
#else
    [DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "SetWindowPos")]
#endif
    public static extern bool SetWindowPos(IntPtr hWnd,
                                           IntPtr hWndInsertAfter,
                                           int X,
                                           int Y,
                                           int cx,
                                           int cy,
                                           uint uFlags);

    public static bool SetWindowPos(IntPtr Handle)
    {
        // 显示状态
        var swp = WindowPosEnum.SWP_NOSIZE | WindowPosEnum.SWP_NOMOVE | WindowPosEnum.SWP_FRAMECHANGED;// 0x23
        return SetWindowPos(Handle, IntPtr.Zero, 0, 0, 0, 0, (uint)swp);// 会触发刷新
    }

    [Flags]
    public enum WindowPosEnum : uint
    {
        SWP_NOSIZE = 0x0001,
        SWP_NOMOVE = 0x0002,
        SWP_NOZORDER = 0x0004,
        SWP_NOREDRAW = 0x0008,
        SWP_NOACTIVATE = 0x0010,
        SWP_FRAMECHANGED = 0x0020,
        SWP_SHOWWINDOW = 0x0040,
        SWP_HIDEWINDOW = 0x0080,
        SWP_NOCOPYBITS = 0x0100,
        SWP_NOOWNERZORDER = 0x0200,
        SWP_NOSENDCHANGING = 0x0400,
        TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE,
    }

    // SetWindowPos用的
    public static readonly IntPtr HWND_TOPMOST = new(-1);
    public static readonly IntPtr HWND_NOTOPMOST = new(-2);
    public static readonly IntPtr HWND_TOP = new(0);


    /// https://www.cnblogs.com/zhuiyi/archive/2012/07/09/2583024.html
    /// <summary>
    /// 设置目标窗体大小,位置(屏幕区坐标)
    /// </summary>
    /// <param name="hWnd">目标句柄</param>
    /// <param name="x">目标窗体新位置X轴坐标</param>
    /// <param name="y">目标窗体新位置Y轴坐标</param>
    /// <param name="nWidth">目标窗体新宽度</param>
    /// <param name="nHeight">目标窗体新高度</param>
    /// <param name="BRePaint">是否刷新窗体</param>
    /// <returns></returns>
    [DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "MoveWindow")]
    public static extern int MoveWindow(IntPtr hWnd, int x, int y, int nWidth, int nHeight, bool BRePaint);

    public static int MoveWindow(IntPtr hWnd, RECT rec, bool BRePaint = true)
    {
        return MoveWindow(hWnd, rec.Left, rec.Top, rec.Width, rec.Height, BRePaint);
    }

    // https://www.cnblogs.com/zhuiyi/archive/2012/07/17/2595309.html
    /// <summary>
    /// 获取窗口客户区的大小,客户区为窗口中除标题栏,菜单栏之外的地方
    /// </summary>
    /// <param name="hwnd"></param>
    /// <param name="lpRect"></param>
    /// <returns></returns>
    [DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "GetClientRect")]
    public static extern bool GetClientRect(IntPtr hwnd, out RECT lpRect);

    /// <summary>
    /// 将指定点的客户区坐标转换为屏幕区坐标
    /// </summary>
    /// <param name="hWnd"></param>
    /// <param name="lpPoint"></param>
    /// <returns></returns>
    [DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "ClientToScreen")]
    public static extern bool ClientToScreen(IntPtr hWnd, ref Point lpPoint);

    [DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "ClientToScreen")]
    public static extern bool ClientToScreen(IntPtr hWnd, ref RECT rect); // 这里可以用吗?

    /// <summary>
    /// 返回指定窗口边框的矩形尺寸,以屏幕左上角为0,0
    /// </summary>
    /// <param name="hwnd"></param>
    /// <param name="lpRect"></param>
    /// <returns></returns>
    [DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "GetWindowRect")]
    public static extern int GetWindowRect(IntPtr hwnd, out RECT lpRect);

    // https://www.cnblogs.com/xtfnpgy/p/9285423.html
    /// <summary>
    /// 嵌入窗口,设置面板在某个面板的下面
    /// </summary>
    /// <param name="hWndChild">嵌入的面板来源</param>
    /// <param name="hWndNewParent">嵌入的面板目标</param>
    /// <returns></returns>
    [DllImport("user32.dll", EntryPoint = "SetParent", SetLastError = true)]
    public static extern int SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

    /// <summary>
    /// 非模态对话框切换焦点
    /// </summary>
    /// <param name="hWnd"></param>
    /// <returns></returns>
    [DllImport("user32.dll", EntryPoint = "SetFocus")]
    public static extern int SetFocus(IntPtr hWnd);

    /// <summary>
    /// 当前焦点位于哪个控件上
    /// </summary>
    /// <returns></returns>
    [DllImport("user32.dll", EntryPoint = "GetFocus", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi)]
    public static extern IntPtr GetFocus();

    /// <summary>
    /// 更新窗口
    /// </summary>
    /// <param name="hWnd"></param>
    /// <returns></returns>
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern bool UpdateWindow(IntPtr hWnd);
}
